home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / qlib205.zip / QLIB.ZIP / SRC / STARTUP / KEYINIT.ASM < prev    next >
Assembly Source File  |  1997-06-11  |  11KB  |  437 lines

  1. ;included by c0.asm
  2.  
  3. ; =========================================================================
  4. ;   Keyboard Driver     Version 1.31
  5. ; =========================================================================
  6. ;  The keyboard driver sets up IRQ handlers and allows better access to the
  7. ;  keyboard which BIOS just can not do.
  8. ;  You can:
  9. ;    - getch(), getche(), getchw(), ungetch()
  10. ;    - block certain keys from being directed RMODE (which will disable
  11. ;      ctrl+break and ctrl+alt+del
  12. ;    - setup lights on the kbd
  13. ;    - block the LOCK keys from going to RMODE
  14. ;  There is also 3 sets of tables maintained by the handler which you can
  15. ;  peek into anytime to see which keys are currently held in.
  16. ;  There are many keys on the keyboard which are a double of another (like
  17. ;  the enter key on the keypad), all these keys are called grey keys and
  18. ;  are preceded by an 0e0h code from the kbd.  When these keys are held in
  19. ;  table#2 is used and if it is not a grey key then table#1 is used.
  20. ;  Table#0 is basically table#1 OR table#2.
  21. ;  So if you don't care which CTRL the user
  22. ;  is holding in just look in table#0.  These tables are each 128 bytes
  23. ;  and each byte is either 1 (held in) or 0 (!held in).  Each byte corresponds
  24. ;  to that keys scan code. (ie: key_tab[1] is the ESC key)
  25. ; =========================================================================
  26.  
  27. ; NEW : ver 1.31
  28. ;  - added _getch() which returns (100h + scan code) if it was a 0 + scan code
  29. ;    key that was pressed.
  30.  
  31. ; NEW : ver 1.3
  32. ;  - total overhaul, now is idendical to ANSI C (which sucks) but now
  33. ;    supports multi-language kbds which is very important
  34. ;  - added ungetch() - NOTE : only one key can be unget at a time
  35.  
  36. ; NEW : ver 1.2
  37. ;  - all IRQs are sent to RMODE (and therefore all LOCKS are handled by BIOS)
  38. ;  - some keys may be blocked from going to RMODE to prevent Ctrl+brk and
  39. ;    ctrl+alt+del (key_block())
  40. ;  - can also prevent LOCK keys from going to RMODE  (key_block_locks())
  41. ;  - 64 byte buffer added
  42. ;  - can set lights (also updates BIOS's flags)
  43.  
  44. ; NEW : ver 1.1
  45. ;  - key_init is now called on startup  (within c0.asm)
  46.  
  47. .data
  48. align 4
  49.   key_tab db 128 dup (0)   ;Table #0  Current keys held in  (1 OR 2)
  50.   key_tab1 db 128 dup (0)  ;Table #1  (keys held in w/o preceding 0e0h)
  51.   key_tab2 db 128 dup (0)  ;Table #2  (keys held in w/ preceding 0e0h)
  52.  
  53.   e0h db 0  ;indicates if the last key typed started with an 0e0h
  54.             ;or an 0e1h (ver 1.2)
  55.             ;this is true on all keypad keys, the right ALT,CTRL
  56.             ;and other things... When this is true key_tab2 is used when
  57.             ;keys are pressed/released (instead of key_tab1)
  58. align 4
  59.   old_int df ?  ;old PMODE IRQ handler
  60.  
  61.   ack db 0      ;ACK that command was sent
  62.   resend db 0   ;resend last command/data
  63.   sending_data db 0  ;flag : currently sending data to kbd
  64.   block_e0 db 0    ;when set all keys starting with 0e0h are not sent to
  65.                      ;RMODE.
  66.                      ; (plus CTRL just in case - to prevent CTRL+ALT+DEL)
  67.                      ; This includes break,del,ins,home,end,pgu,pgd,arrow keys,
  68.                      ;  right ctrl,right alt,enter(on keypad only)
  69.                      ; Great to disable Ctrl+break and Ctrl+alt+del.
  70.                      ;  Use key_block(x) to do this. (1=YES  0=NO)
  71.  
  72.   paws db 0          ;Pause key sequence is coming (e1 1d 45 e1 9d c5)
  73.   block_locks db 0   ;when set all LOCK keys are not sent to RMODE
  74.   ungetch_flg db 0   ;set if a key is waiting for getch using ungetch
  75.   ungetch_char db 0  ;char waiting when using ungetch
  76.  
  77. .code
  78. ; waits till kbd is not busy
  79. kb_wait proc private
  80.   ;don't use edx!!
  81.   mov ecx,10000h
  82. @@:
  83.   in al,64h
  84.   test al,2
  85.   jz @f
  86.   dec ecx
  87.   jnz @b
  88. @@:
  89.   ret
  90. kb_wait endp
  91.  
  92. align 4
  93. ;send data to kbd
  94. key_send proc private,data:byte
  95.   mov edx,3   ;# of reties
  96. retry:
  97.   call kb_wait
  98.   mov ack,0
  99.   mov resend,0
  100.   mov al,data
  101.   out 60h,al
  102.   mov ecx,20000h
  103. @@:
  104.   push edx        ;
  105.   mov dx,388h     ;non-destructive port
  106.   in al,dx        ;
  107.   pop edx         ;waste some time
  108.   .if ack
  109.     xor eax,eax
  110.     ret
  111.   .endif
  112.   .if resend
  113.     dec edx
  114.     jnz retry
  115.     mov eax,1    ;did not send
  116.     ret
  117.   .endif
  118.   dec ecx
  119.   jnz @b
  120.   mov eax,1    ;did not send
  121.   ret
  122. key_send endp
  123.  
  124. ;this empty's the kbd input/output buffers  (scraps everything)
  125. empty_8042 proc private
  126.   call _delay
  127.   in al,64h
  128.   test al,1
  129.   jz no_output
  130.   call _delay
  131.   in al,60h
  132.   jmp empty_8042
  133. no_output:
  134.   test al,2
  135.   jnz empty_8042
  136.   ret
  137. empty_8042 endp
  138.  
  139. ;sets the lights on the kbd and updates the BIOS flags
  140. key_lights proc,a:byte
  141.   mov sending_data,1    ;we are sending data!
  142.   callp empty_8042
  143.   callp key_send,0edh     ;send set lights command
  144.   .if eax    ;successful?
  145.     mov sending_data,0  ;nope!
  146.     ret
  147.   .endif
  148.   callp key_send,a        ;send data  (bits 0-2 are the lights)
  149.   .if eax
  150.     mov sending_data,0
  151.     ret
  152.   .endif
  153.  
  154. ;update BIOS flags
  155.   .if a & 1  ;SCROOL LOCK bit
  156.     or byte ptr gs:[417h],(1h SHL 4)
  157.   .else
  158.     and byte ptr gs:[417h],0ffh XOR (1h SHL 4)
  159.   .endif
  160.   .if a & 4  ;CAPS
  161.     or byte ptr gs:[417h],(1 SHL 6)
  162.   .else
  163.     and byte ptr gs:[417h],0ffh XOR (1h SHL 6)
  164.   .endif
  165.   .if a & 2  ;NUM LOCK
  166.     or byte ptr gs:[417h],(1 SHL 5)
  167.   .else
  168.     and byte ptr gs:[417h],0ffh XOR (1h SHL 5)
  169.   .endif
  170.   mov sending_data,0  ;done sending data
  171.   xor eax,eax
  172.   ret
  173. key_lights endp
  174.  
  175. _delay proc private
  176.   jmp $+2
  177.   ret
  178. _delay endp
  179.  
  180. align 4
  181. ;PMODE IRQ handler
  182. key_pmirq:
  183.   call key_irqhand
  184.   sti
  185.   iretd
  186.  
  187. align 4
  188. ;this is the main IRQ handler
  189. key_irqhand proc private
  190.   push ds
  191.   push es
  192.   push gs
  193.   pushad
  194.   mov ds,cs:seldata
  195.   mov es,seldata
  196.   mov gs,selzero
  197.   call kb_wait
  198.   xor eax,eax
  199.   in al,60h  ;get data from kbd
  200.   .if paws   ;if the paws sequence is coming then just ignore the data
  201.     dec paws
  202.     .if block_e0   ;if 0e0h is disabled then just IRET
  203.       jmp key_done
  204.     .endif
  205.     jmp key_iend     ;else redirect to RMODE
  206.   .endif
  207.   .if al==0fah   ;ACK (means the kbd successfully recieved the command/data)
  208.     .if sending_data  ;if we are sending data to the kbd we need the ACK
  209.       mov ack,1
  210.       jmp key_done
  211.     .endif
  212.     jmp key_iend      ;else send to RMODE
  213.   .endif
  214.   .if al==0feh  ;resend  (means kbd did not get command/data)
  215.     .if sending_data
  216.       mov resend,1
  217.       jmp key_done
  218.     .endif
  219.     jmp key_iend
  220.   .endif
  221.   .if sending_data    ;ignore everything else while sending data
  222.     jmp key_done
  223.   .endif
  224.   .if al==0e0h     ;it's the 0e0h prefix  (next key is a grey key)
  225.     mov e0h,1           ;set flag
  226.     .if block_e0        ;block e0h from going to RMODE?
  227.       jmp key_done      ;yes
  228.     .endif
  229.     jmp gotoRMODE       ;no
  230.   .endif
  231.   .if al==0e1h          ;this is the 1st byte of the PAUSE sequence
  232.     mov paws,5        ;ignore next 5 codes
  233.     mov e0h,1         ;the PAUSE key is considered to have a 0e0h prefix
  234.     jmp key_iend      ;so that if you disable 0e0h this will also not goto RMODE
  235.   .endif
  236.   .if (e0h)   ;detect wachy keys
  237.     .if al==37h  ;Print Screen make (e0 2a e0 37)
  238.       mov al,7eh  ;this is the new scan code (look in toascii for it's ASCII)
  239.       mov e0h,0
  240.     .elseif al==0b7h  ;print screen break (e0 b7 e0 aa)
  241.       mov e0h,0
  242.       mov al,7eh+80h
  243.     .elseif al==46h   ;Ctrl+brk code (e0 46 e0 c6)  (ignored)
  244.       jmp key_iend    ;
  245.     .elseif al==0aah  ;
  246.       jmp key_iend    ;
  247.     .elseif al==2ah   ;
  248.       jmp key_iend    ;
  249.     .elseif al==0c6h  ;
  250.       jmp key_iend    ;  other stuff I must ignore
  251.     .elseif al==036h  ;
  252.       jmp key_iend    ;
  253.     .elseif al==0b6h  ;
  254.       jmp key_iend    
  255.     .endif
  256.   .else
  257.     .if al==54h
  258.       mov al,7eh
  259.     .elseif al==0d4h
  260.       mov al,7eh+80h
  261.     .endif
  262.   .endif
  263.   mov ebx,offset key_tab
  264.   add ebx,eax
  265. ;when bit 7 of al =1 then al=(scan code of key released + 128)
  266. ;                 =0 then al=(scan code of key pressed)
  267.   test al,128
  268.   jz @f
  269. ;key released
  270.   sub ebx,128  ;remove 80h from al
  271.   .if e0h  ;was last byte 0e0h?
  272.     add ebx,256    ;goto tab2
  273.     mov byte ptr[ebx],0
  274.     sub ebx,128    ;goto tab1
  275.     .if !byte ptr[ebx]
  276.       sub ebx,128  ;goto tab
  277.       mov byte ptr[ebx],0
  278.     .endif
  279.   .else
  280.     add ebx,128    ;goto tab1
  281.     mov byte ptr[ebx],0
  282.     add ebx,128    ;goto tab2
  283.     .if !byte ptr[ebx]
  284.       sub ebx,256  ;goto tab
  285.       mov byte ptr[ebx],0
  286.     .endif
  287.   .endif
  288.   jmp key_iend
  289. @@:
  290. ;key pressed
  291.   mov byte ptr[ebx],1
  292.   .if e0h
  293.     add ebx,256   ;goto tab2
  294.     mov byte ptr[ebx],1
  295.   .else
  296.     add ebx,128   ;goto tab1
  297.     mov byte ptr[ebx],1
  298.   .endif
  299. key_iend:  
  300.   .if (block_e0) && (e0h)
  301.     mov e0h,0
  302.     jmp key_done  ;do not redirect to RMODE
  303.   .endif
  304.   mov e0h,0
  305.   .if (block_e0) && (al==1dh)   ;stop CTRL from going to RMODE
  306.     jmp key_done   ;do not redirect to RMODE
  307.   .endif
  308.   .if block_locks
  309.     .if (al==3ah) || (al==45h) || (al==46h)  ;disable LOCK keys
  310.       jmp key_done ;do not redirect to RMODE
  311.     .endif
  312.   .endif
  313. gotoRMODE:
  314. ;call old int #9
  315.   pushfd
  316.   call old_int
  317.   jmp @f
  318. key_done:
  319.   mov al,20h
  320.   out 20h,al
  321. @@:
  322.   popad
  323.   pop gs
  324.   pop es
  325.   pop ds
  326.   ret
  327. key_irqhand endp
  328.  
  329. key_init proc private
  330.   callp getint,9
  331.   mov wptr[old_int+4],ax
  332.   mov dptr[old_int],edx
  333.   mov cx,cs
  334.   callp setint,9,cx,offset key_pmirq
  335.   ret
  336. key_init endp
  337.  
  338. align 4
  339. getchar proc uses ebx
  340.   jmp _getch_  ;it's the EXACT same
  341. getchar endp
  342.  
  343. getch proc uses ebx
  344.   ;waits till a key is pressed
  345. _getch_::
  346.   .if ungetch_flg
  347.     xor eax,eax
  348.     mov al,ungetch_char
  349.     mov ungetch_flg,0
  350.     ret
  351.   .endif
  352.   mov ax,700h
  353.   int 21h
  354.   movzx eax,al
  355.   ret
  356. getch endp
  357.  
  358. _getch proc
  359.   call getch
  360.   .if !al
  361.     call getch
  362.     inc ah  ;100h
  363.   .endif
  364.   ret
  365. _getch endp
  366.  
  367. getchw proc uses ebx ;get key w/o waiting
  368.   ;does NOT wait till a key is pressed
  369.   call kbhit
  370.   .if eax
  371.     call getch
  372.   .endif
  373.   ret
  374. getchw endp
  375.  
  376. dat db ?
  377.  
  378. getche proc
  379.   call getch
  380.   push ax
  381.   mov dat,al
  382.   invoke write,1,offset dat,1
  383.   pop ax
  384.   ret
  385. getche endp
  386.  
  387. kbhit proc
  388.   .if ungetch_flg
  389.     mov eax,1
  390.     ret
  391.   .endif
  392.   mov ah,0bh
  393.   int 21h
  394.   movzx eax,al
  395.   ret
  396. kbhit endp
  397.  
  398. key_block proc,x:byte      ;Block some keys from going to RMODE
  399.   mov al,x                   ;this will prevent PAUSE,Ctrl^brk,Ctrl^alt^del
  400.   .if al                     ;plus much more
  401.     mov al,1
  402.   .else
  403.     mov al,0
  404.   .endif
  405.   mov block_e0,al
  406.   xor eax,eax
  407.   ret
  408. key_block endp
  409.  
  410. ;if you want to set the lights are stop the user from changing them then:
  411. ;  key_block_locks(1)
  412. ;  key_lights(x)   ;set lights
  413. key_block_locks proc,x:byte ;Block NUM/CAPS/SCROLL LOCKS from going to RMODE
  414.   mov al,x
  415.   .if al
  416.     mov al,1
  417.   .else
  418.     mov al,0
  419.   .endif
  420.   mov block_locks,al
  421.   and byte ptr gs:[418h],0ffh XOR (5 shl 4)     ;shut off keys in BIOS
  422.   xor eax,eax
  423.   ret
  424. key_block_locks endp
  425.  
  426. ungetch proc,a:byte
  427.   .if ungetch_flg
  428.     mov eax,ERROR
  429.     ret
  430.   .endif
  431.   mov al,a
  432.   mov ungetch_char,al
  433.   mov ungetch_flg,1
  434.   xor eax,eax
  435.   ret
  436. ungetch endp
  437.